package org.noootsab.gae.games.tzaar.model.game {
import flash.utils.IDataInput;
import flash.utils.IDataOutput;
import flash.utils.IExternalizable;

import mx.collections.ArrayCollection;
import mx.logging.ILogger;
import mx.logging.Log;

import org.noootsab.gae.games.tzaar.event.GameEvent;
import org.noootsab.gae.games.tzaar.model.*;
import org.noootsab.gae.games.tzaar.model.player.Player;

[Bindable]
[RemoteClass(alias="org.noootsab.gae.games.tzaar.model.Game")]
[Event(name="start", type="org.noootsab.gae.games.tzaar.event.GameEvent")]
[Event(name="play", type="org.noootsab.gae.games.tzaar.event.GameEvent")]
[Event(name="finish", type="org.noootsab.gae.games.tzaar.event.GameEvent")]
public class Game implements IExternalizable {
    private static const LOG:ILogger = Log.getLogger("org.noootsab.gae.games.tzaar.model.game.Game");

    public var key:String;
    public var gameId:String;
    public var white:String;
    public var black:String;
    public var winner:Player;

    public var currentState:GameState;
    public var boardConfiguration:BoardConfiguration;

    public var history:Array;

    public function Game() {
    }

    public function init(boardConfiguration:BoardConfiguration = null):void {
        if (boardConfiguration === null) {
            this.boardConfiguration = new BoardConfiguration();
            this.boardConfiguration.init(this, true);
        } else {
            this.boardConfiguration = boardConfiguration;
        }
    }

    public function joinBy(player:Player):void {
        if (white == null) {
            white = player.key
        } else if (black == null) {
            black = player.key;
        }
    }

    public function start():void {
        if (white === null || black === null) {
            throw new Error("Game asked to be started but players are missing!");
        }
        this.currentState = GameState.getStartedState(this);
        dispatchEvent(new GameEvent(GameEvent.START, false, false));
    }

    public function play(action:GameAction):void {
        if (currentState.currentPlayer !== Tzaar.loggedInPlayer.key) {
            throw new Error("Current user can't play... It's not your turn!");
        }
        currentState.setAction(action);
        var previousState:GameState = currentState;
        currentState = GameState.getNextState(this, previousState);
        if (currentState.winner === null) {
            dispatchEvent(new GameEvent(GameEvent.PLAY, false, false));
        } else {
            dispatchEvent(new GameEvent(GameEvent.FINISH, false, false));            
        }
        if (currentState.previousState !== null && currentState.currentPlayer !== currentState.previousState.currentPlayer) {
            dispatchEvent(new GameEvent(GameEvent.TURN_CHANGED, false, false));
        }
    }

    public function isBlack(player:String):Boolean {
        LOG.info("Is Black? " + player + " -- white " + white + " ... black " + black + "  ->  result " + (player === black) + " -- other " + (player == black));
        return player === black;
    }

    public function opponent(player:String):String {
        return player === white ? black : white;
    }

    public function readExternal(input:IDataInput):void {
        key = input.readObject() as String;

        gameId = input.readObject() as String;

        var ps:Array = (input.readObject() as ArrayCollection).toArray();
        if (ps != null) {
            if (ps.length > 0) {
                white = ps[0];
                if (ps.length == 2) {
                    black =ps[1];
                }
            }
        }

        winner =  (input.readObject() as Player);

        var jsonString:String = input.readObject() as String;
        if (jsonString !== null) {
            boardConfiguration = BoardConfiguration.fromJSON(this, jsonString);
        }

        jsonString = input.readObject() as String;
        if (jsonString !== null) {
            currentState = GameState.fromJSON(this, jsonString);
        }
    }

    public function writeExternal(output:IDataOutput):void {
        output.writeObject(key);

        output.writeObject(gameId);
        
        //started
        var started:Boolean = currentState !== null;
        output.writeObject(started );

        //finished
        var finished:Boolean = currentState !== null && currentState.winner !== null;
        output.writeObject(finished);

        //winnerBlack
        if (winner !== null) {
            output.writeObject(winner.key === black);
        } else {
            output.writeObject(null);
        }

        //players
        output.writeObject(new ArrayCollection([white, black]));

        if (boardConfiguration !== null) {
            output.writeObject(BoardConfiguration.toJSON(boardConfiguration));
        } else {
            output.writeObject(null);
        }

        if (currentState !== null) {
            output.writeObject(GameState.toJSON(currentState));
        } else {
            output.writeObject(null);
        }
    }

}
}